from __future__ import annotations

import subprocess
from pathlib import Path


def _run(cmd: list[str], cwd: Path) -> tuple[int, str, str]:
    p = subprocess.Popen(cmd, cwd=str(cwd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    out, err = p.communicate()
    return p.returncode, out, err


def _ensure_repo(home: Path) -> bool:
    return (home / ".git").exists()


def sync_init(home: Path, remote: str | None, branch: str) -> None:
    if not _ensure_repo(home):
        code, out, err = _run(["git", "init", "-b", branch], home)
        if code != 0:
            raise SystemExit(f"git init failed: {err.strip()}")
    # .gitignore sensible defaults
    gi = home / ".gitignore"
    if not gi.exists():
        gi.write_text("\n".join([
            "logs/",
            "index/",
            "export/",
            "attachments/",
        ]) + "\n", encoding="utf-8")
    # initial commit if none
    _run(["git", "add", "-A"], home)
    _run(["git", "commit", "-m", "chore: init workspace"], home)
    if remote:
        _run(["git", "remote", "remove", "origin"], home)  # ignore errors
        code, out, err = _run(["git", "remote", "add", "origin", remote], home)
        if code != 0 and "already exists" not in err:
            raise SystemExit(f"git remote add failed: {err.strip()}")
    print(f"Repo ready at {home}")


def sync_status(home: Path) -> None:
    code, out, err = _run(["git", "status", "--porcelain", "-b"], home)
    if code != 0:
        print("Not a git repo or error:", err.strip())
        return
    print(out.rstrip())


def sync_push(home: Path, remote: str, branch: str) -> None:
    _run(["git", "add", "-A"], home)
    _run(["git", "commit", "-m", "chore: workspace update"], home)
    code, out, err = _run(["git", "push", remote, branch], home)
    if code != 0:
        raise SystemExit(f"git push failed: {err.strip() or out.strip()}")
    print(out.rstrip())


def sync_pull(home: Path, remote: str, branch: str) -> None:
    code, out, err = _run(["git", "pull", "--rebase", remote, branch], home)
    if code != 0:
        raise SystemExit(f"git pull failed: {err.strip() or out.strip()}")
    print(out.rstrip())


def sync_set_remote(home: Path, name: str, url: str) -> None:
    if not url:
        raise SystemExit("--remote URL required")
    _run(["git", "remote", "remove", name], home)
    code, out, err = _run(["git", "remote", "add", name, url], home)
    if code != 0:
        raise SystemExit(f"git remote add failed: {err.strip() or out.strip()}")
    print(f"remote '{name}' set -> {url}")
